package com.tyhy.program.cbc.mobileapi.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import com.tyhy.program.cbc.mobileapi.constants.RedisIndex;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

@Component
public class RedisManager {

    /**
     * 获取锁成功标志
     */
    private static final String LOCK_SUCCESS = "OK";
    /**
     * SET IF NOT EXIST，即当key不存在时，我们进行set操作；若key已经存在，则不做任何操作；
     */
    private static final String SET_IF_NOT_EXIST = "NX";
    /**
     * 过期设置
     */
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    /**
     * 释放锁成功标志
     */
    private static final Long RELEASE_SUCCESS = 1L;

    @Value("${spring.redis.host}")
    private String host = "127.0.0.1";

    @Value("${spring.redis.port}")
    private int port = 6379;
    
    // 0 - never expire
    private int expire = 0;

    // timeout for jedis try to connect to redis server, not expire time! In
    // milliseconds
    @Value("${spring.redis.timeout}")
    private int timeout = 0;

    @Value("${spring.redis.password}")
    private String password = "";

    private static JedisPool jedisPool = null;

    public RedisManager() {

    }

    /**
     * 初始化方法
     */
    @Bean
    public JedisPool initJedisPool() {
        if (jedisPool == null) {
            if (password != null && !"".equals(password)) {
                jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password);
            } else if (timeout != 0) {
                jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout);
            } else {
                jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
            }

        }
        return jedisPool;
    }

    public void init() {
        if (jedisPool == null) {
            if (password != null && !"".equals(password)) {
                jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password);
            } else if (timeout != 0) {
                jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout);
            } else {
                jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
            }

        }
    }

    /**
     * get value from redis
     *
     * @param key
     * @return
     */
    public byte[] get(byte[] key) {
        byte[] value = null;
        Jedis jedis = jedisPool.getResource();
        try {
            value = jedis.get(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    public String get(String key) {
        String value = null;
        Jedis jedis = jedisPool.getResource();
        try {
            value = jedis.get(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    public byte[] get(byte[] key,int dbIndex) {
        byte[] value = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            value = jedis.get(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    /**
     * redis是否存在key值
     *
     * @param key
     * @param dbIndex
     * @return
     */
    public boolean exists(String key, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        boolean value = false;
        try {
            value = jedis.exists(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }


    /**
     * set
     *
     * @param key
     * @param value
     * @return
     */
    public byte[] set(byte[] key, byte[] value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (this.expire != 0) {
                jedis.expire(key, this.expire);
            }
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    public void set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (this.expire != 0) {
                jedis.expire(key, this.expire);
            }
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * set
     *
     * @param key
     * @param value
     * @param expire
     * @return
     */
    public void set(String key, String value, int expire) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * set
     *
     * @param key
     * @param value
     * @param expire
     * @return
     */
    public byte[] set(byte[] key, byte[] value, int expire) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    /**
     * set
     *
     * @param key
     * @param value
     * @param expire
     * @return
     */
    public byte[] set(byte[] key, byte[] value, int expire,int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    /**
     * del
     *
     * @param key
     */
    public void del(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public void del(String key,Integer dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }


    /**
     * 获取jedis对象，并指定dbIndex
     *
     * @param dbIndex
     */
    public Jedis getJedis(Integer dbIndex) {
        Jedis jedis = jedisPool.getResource();
        if (dbIndex == null || dbIndex > 15 || dbIndex < 0) {
            dbIndex = 0;
        }
        jedis.select(dbIndex);
        return jedis;
    }

    public String setRedisString(String key, String value, int dbIndex) {
        String String = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            String = jedis.set(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return String;
    }

    public String getsetRedisString(String key, String value, int dbIndex) {
        String String = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            String = jedis.getSet(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return String;
    }

    public void removeRedisString(String key, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 超时时间
     *
     * @param key
     * @param dbIndex
     * @param expire
     */
    public void setExpire(String key, int expire, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 链表,追加到尾部
     *
     * @param key
     * @param value
     * @param dbIndex
     */
    public void setRedisRpush(String key, String value, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.rpush(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 链表,追加到头部
     *
     * @param key
     * @param value
     * @param dbIndex
     */
    public Long setRedisLpush(String key, String value, int dbIndex) {
        Long lpush = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            lpush = jedis.lpush(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return lpush;
    }

    public String getRedisString(String key, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        String value = null;
        try {
            value = jedis.get(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    public List<String> getRedisList(String key, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        List<String> lrange = null;
        try {
            lrange = jedis.lrange(key, 0, -1);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return lrange;
    }

    /**
     * del
     *
     * @param key
     */
    public void remove(String key, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * flush
     */
    public void flushDB() {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.flushDB();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * size
     */
    public Long dbSize() {
        Long dbSize = 0L;
        Jedis jedis = jedisPool.getResource();
        try {
            dbSize = jedis.dbSize();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return dbSize;
    }

    /**
     * keys
     *
     * @return
     */
    public Set<byte[]> keys(String pattern) {
        Set<byte[]> keys = null;
        Jedis jedis = jedisPool.getResource();
        try {
            keys = jedis.keys(pattern.getBytes());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return keys;
    }


    /**
     * 发布
     */
    public void publish(String topic, String message) {
        Jedis jedis = getJedis(RedisIndex.INDEX_5);
        try {
            jedis.publish(topic, message);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 如果哈希表不存在，一个新的哈希表被创建并进行 HSET 操作。
     * 如果字段已经存在于哈希表中，旧值将被覆盖。
     */
    public String setHashString(String key, String field, String value, int dbIndex) {
        String String = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.hset(key, field, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return String;
    }

    public String delHash(String key, String field, int dbIndex) {
        String String = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.hdel(key, field);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return String;
    }

    public void sadd(String key, String value, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            jedis.sadd(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public Set<String> smembers(String key, int dbIndex) {
        Set<String> smembers = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            smembers = jedis.smembers(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return smembers;
    }

    public String getHashString(String key, String field, String value, int dbIndex) {
        String hget = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            hget = jedis.hget(key, field);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return hget;
    }

    public Map<String, String> getHashAll(String key, int dbIndex) {
        Map<String, String> map = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            map = jedis.hgetAll(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return map;
    }

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey    锁
     * @param requestId  请求标识
     * @param expireTime 超期时间
     * @param dbIndex    库索引
     * @return 是否获取成功
     */
//    public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime, int dbIndex) {
//        Jedis jedis = getJedis(dbIndex);
//        try {
//            String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
//            if (LOCK_SUCCESS.equals(result)) {
//                return true;
//            }
//        } finally {
//            if (jedis != null) {
//                jedis.close();
//            }
//        }
//        return false;
//    }

    /**
     * 释放分布式锁
     *
     * @param lockKey   锁
     * @param requestId 请求标识
     * @param dbIndex   库索引
     * @return 是否释放成功
     */
    public boolean releaseDistributedLock(String lockKey, String requestId, int dbIndex) {
        Jedis jedis = getJedis(dbIndex);
        try {
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return false;
    }

    /**
     * 设置key及超时时间
     *
     * @param key
     * @param value
     * @param dbIndex
     * @return
     */
    public String setEx(String key, int seconds, String value, int dbIndex) {
        String String = null;
        Jedis jedis = getJedis(dbIndex);
        try {
            String = jedis.setex(key, seconds, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return String;
    }

   


    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getExpire() {
        return expire;
    }

    public void setExpire(int expire) {
        this.expire = expire;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}
